package plotagem;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.Channels;
import java.text.Normalizer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;

import org.json.JSONArray;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileService;
import com.google.appengine.api.files.FileServiceFactory;
import com.google.appengine.api.files.FileWriteChannel;
import com.google.appengine.api.files.FinalizationException;
import com.google.appengine.api.files.LockException;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;

import entidades.ArquivosUsuario;
import entidades.Usuarios;
import entidades.Visitas;


public class Utilidades {
	static FileService fileService = FileServiceFactory.getFileService();
	private static MemcacheService keycache = MemcacheServiceFactory.getMemcacheService();
	//private static PersistenceManager pm = PMF.get().getPersistenceManager();
	private static UserService userService = UserServiceFactory.getUserService();
	private static User user = userService.getCurrentUser();

// Consulta as informações armazenadas no SortedMap do usuário
	public static SortedMap<String,String[]> consultarArquivosUsuario(String Usuario){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		SortedMap<String,String[]> mapaArquivos = null;
		Key k = KeyFactory.createKey(ArquivosUsuario.class.getSimpleName(), Usuario);
		try{
			try{
				ArquivosUsuario arquivosUsuario = pm.getObjectById(ArquivosUsuario.class,k);
				mapaArquivos = arquivosUsuario.getMapa();
			}catch(JDOObjectNotFoundException e){
				e.printStackTrace();
			}

		} finally {
	        pm.close();
	    }
		return mapaArquivos;
	}
// Adiciona informações de um upload no SortedMap do usuário	
	public static void adicionarNoMapa(String Usuario, String chave, String[] lista){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key k = KeyFactory.createKey(ArquivosUsuario.class.getSimpleName(), Usuario);
		try{
			try{
				ArquivosUsuario arquivosUsuario = pm.getObjectById(ArquivosUsuario.class,k);
				SortedMap<String,String[]> mapaArquivos = arquivosUsuario.getMapa();
				String Skey = arquivosUsuario.getSKey();
				mapaArquivos.put(chave, lista);
				arquivosUsuario = new ArquivosUsuario(Skey,Usuario,mapaArquivos);
				pm.makePersistent(arquivosUsuario);
			}catch(Exception e){
				SortedMap<String,String[]> NOVO_ARQUIVOS_USUARIO = new TreeMap<String,String[]>();
				NOVO_ARQUIVOS_USUARIO.put(chave, lista);
				String Skey_usuario = KeyFactory.createKeyString("ArquivosUsuario", Usuario);
				ArquivosUsuario novo_arquivosUsuario = new ArquivosUsuario(Skey_usuario, Usuario, NOVO_ARQUIVOS_USUARIO);
				pm.makePersistent(novo_arquivosUsuario);
			}
		} finally {
	        pm.close();
	    }
	}
// Deleta informações de um upload no SortedMap do usuário	
	public static void deletarDoMapa(String Usuario, String chave){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key k = KeyFactory.createKey(ArquivosUsuario.class.getSimpleName(), Usuario);
		try{
			try{
				ArquivosUsuario arquivosUsuario = pm.getObjectById(ArquivosUsuario.class,k);
				SortedMap<String,String[]> mapaArquivos = arquivosUsuario.getMapa();
				String Skey = arquivosUsuario.getSKey();
				mapaArquivos.remove(chave);
				arquivosUsuario = new ArquivosUsuario(Skey,Usuario,mapaArquivos);
				pm.makePersistent(arquivosUsuario);
			}catch(Exception e){
				e.printStackTrace();
			}
		} finally {
	        pm.close();
	    }
	}
// Tem por objetivo contar o número de pageviews e monitorar o uso da cota gratuita de 5000000 	
	public static long nrGeral(){
		long nrGeral = 1;
		DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
		Query query = new Query("Visitas");
		query.addSort("nrGeral",SortDirection.DESCENDING);
		PreparedQuery pq = ds.prepare(query);
		List<Entity>result = pq.asList(FetchOptions.Builder.withLimit(1));
		if (result!=null){
			for (Entity entity:result){
				Entity entidade = entity;
				nrGeral = (Long) entidade.getProperty("nrGeral");
			}
		}
		return nrGeral;
	}
// Tem por objetivo contar o número de pageviews e monitorar o uso da cota gratuita de 5000000 	
	public static void registraVisita(){
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Key k = KeyFactory.createKey(Usuarios.class.getSimpleName(), user.getNickname());
		Visitas visita = new Visitas(new Date(),nrGeral()+1);
		Transaction tx = pm.currentTransaction();
		try{
	        tx.begin();
			try{
				Usuarios usuario = pm.getObjectById(Usuarios.class,k);
				usuario.setVisita(visita);
				pm.makePersistent(usuario);
			}catch(Exception e){
				String Skey_nickname = KeyFactory.createKeyString("Usuarios", user.getNickname());
				Usuarios usuario = new Usuarios(Skey_nickname, user.getNickname(), user.getEmail());
				pm.makePersistent(usuario);
				usuario = pm.getObjectById(Usuarios.class,k);
				usuario.setVisita(visita);
				pm.makePersistent(usuario);
			}
			tx.commit();
		} finally {
	        if (tx.isActive()) {
	            tx.rollback();
	        }
	    }
	}
// Apresentar a data de upload que será exibida na aplicação em um formato amigo	
	public static String dt(Date data){
		//TimeZone.setDefault(TimeZone.getTimeZone("GMT-5:00"));
		String Dt = null;
		SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
		Dt = formato.format(data);
		return Dt;
	}
//Tabela que será exibida no espaço lateral da Aplicação	
	public static String TabelaArquivos(String Usuario) throws UnsupportedEncodingException{
		SortedMap<String,String[]> mapaArquivos = consultarArquivosUsuario(Usuario);
		StringBuffer tabela = new StringBuffer("<table class='TabArq'>");
		tabela.append("<tr><th class='colArqNome'>Nome</th><th class='colArqData'>Data</td><th class='colArq'>Txt(Orig.)</th><th class='colArq'>Kml</th>");
		tabela.append("<th class='colArq'>Erros</th><th class='colArq'>Deletar</th><th class='colArq'>Ver</th></tr>\n");
		if(mapaArquivos!=null){
			for(Entry<String, String[]> it : mapaArquivos.entrySet())	{
				String chave = it.getKey();
				String lista[]=it.getValue();
				tabela.append("<tr><td class='tdArqNome'>").append(lista[0]).append("</td><td class='tdArq'>").append(lista[1]).append("</td><td class='tdArq'><a href='/pedido?blob-key=");
				tabela.append(lista[2]).append("'>baixar</a></td><td class='tdArq'><a href='/pedido?escrever=").append(chave).append("'>baixar</a></td>");
				tabela.append("<td class='tdArq'><a href='/pedido?blob-key=").append(lista[4]).append("'>baixar</a></td>");
				tabela.append("<td class='tdArq'><a href='/pedido?deletar=").append(chave).append("'>deletar</a></td>");
				tabela.append("<td class='tdArq'><a href='/pedido?ver=").append(chave).append("'>ver</a></td>");
				tabela.append("</tr>\n");
			}
		}
		tabela.append("</table>\n");
		return tabela.toString();
	}
//Abre, escreve e fecha o arquivo 
	public static void escreverArquivo(String texto, String path) throws FileNotFoundException, FinalizationException, LockException, IOException{
		AppEngineFile arquivo = new AppEngineFile(path);
		FileWriteChannel writeChannel = fileService.openWriteChannel(arquivo, true);
		PrintWriter out = new PrintWriter(Channels.newWriter(writeChannel, "UTF8"));
        out.print(texto);
        out.close();
	}
//Busca de coordenadas, inicialmente no cache e, posteriormente, no Google Geocode
//As informações são fornecidas no formato Json
	public static StringBuffer solicitarCoordenadas(String endereco){
		String urlString = "http://maps.google.com/maps/api/geocode/json?components=country:BR&address="+endereco+"&sensor=false&language=pt-BR";
		String Skey_endereco = KeyFactory.createKeyString("Enderecos", endereco);
		StringBuffer ResultadoCache = (StringBuffer) keycache.get(Skey_endereco);
		StringBuffer resultado= new StringBuffer("");
		if(ResultadoCache==null){
			try {
				URL url = new URL(urlString);
				try {
					HttpURLConnection connection = (HttpURLConnection) url.openConnection();
					// seta o metodo  
					connection.setRequestProperty("Request-Method", "GET"); 
					// seta a variavel para ler o resultado  
					connection.setDoInput(true);  
					connection.setDoOutput(false);
					// conecta com a url destino  
					connection.connect();
					// abre a conexão pra input  
					BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
					// lê até o final  
					String s = "";  
					while (null != ((s = br.readLine()))) {  
						resultado.append(s); 
					}
					keycache.put(Skey_endereco, resultado);
					br.close();  
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 
			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else{
			resultado = ResultadoCache;
		}
		return resultado;
	}
//Prepara o endereço para consulta	
	public static String gerarStringEndereco(String endereco){
		try{
			endereco = Normalizer.normalize(endereco, Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", "");
			endereco = endereco.replaceAll(" ", "\\+");
			endereco = endereco.replaceAll("\\+-\\+", "\\+");
		} catch( Exception e) {
			e.printStackTrace();
		}
		return endereco;
	}
//prepara o html que será usado no kml. O html das infowindows é preparado em Javascript na JSP	
	public static String plotarHtml(JSONArray EnderecosEncontrados, String[] titulos){
		StringBuffer html = new StringBuffer("");
		html.append("<html><head><link rel='stylesheet' type='text/css' href='http://plotagemkml.appspot.com/css/geral.css'></head><body><h5>");
		html.append(EnderecosEncontrados.get(0)).append("</h5><table class='TabPlace'>");
		html.append("<th class='colPlaceNome'>Nome</th><th class='colPlaceValor'>Valor</th></tr>");
		for(int i = 1;i<EnderecosEncontrados.length();i++){
			html.append("<tr><td class='tdPlaceNome'>").append(titulos[i]).append("</td><td class='tdPlaceValor'>").append(EnderecosEncontrados.get(i)).append("</td></tr>");
	    }
		html.append("</table></body></html>");
		return html.toString();
	}
/*Desativado quando os dados do mapa e da tabela de endereços encontrados foram unidos em uma única tabela
* 	
*	public static String PlotarDadosInfoWindow(String[] coordenadas, String[] dados, String[] titulos){
*		StringBuffer dadosInfoWindow = new StringBuffer("");
*		dadosInfoWindow.append("{ titulo : \"").append(dados[0]).append("\" , ");
*		dadosInfoWindow.append(" variaveis : { ");
*		for(int i = 0;i<dados.length;i++){
*			if(i>0){dadosInfoWindow.append(" , ");}
*			dadosInfoWindow.append(" \"").append(titulos[i]).append("\" : \"").append(dados[i]).append("\"");
*	    }
*		dadosInfoWindow.append(" } ");
*		dadosInfoWindow.append(" , enderecoEncontrado : \"").append(coordenadas[2]);
*		dadosInfoWindow.append("\" , Latitude : \"").append(coordenadas[0]).append("\" , Longitude : \"").append(coordenadas[1]).append("\" }");
*		return dadosInfoWindow.toString();
*	}
*/
	
//Plota o placemark do kml
//Aqui podem ser aplicadas as personalizações do placemark
	public static StringBuffer plotarPlacemark(JSONArray EnderecosEncontrados, String html){
		StringBuffer placemark=new StringBuffer("");
		int tam = EnderecosEncontrados.length();
			try{
		        placemark.append("\n").append("	<Placemark>");
		        placemark.append("\n").append("		<name>").append(EnderecosEncontrados.get(0)).append("</name>");
		        placemark.append("\n").append("		<description><![CDATA[").append(html).append("]]></description>");
		        placemark.append("\n").append("		<LookAt>");
		        placemark.append("\n").append("			<longitude>").append(EnderecosEncontrados.get(tam-2)).append("</longitude>");
		        placemark.append("\n").append("			<latitude>").append(EnderecosEncontrados.get(tam-3)).append("</latitude>");
		        placemark.append("\n").append("			<altitude>0</altitude>");
		        placemark.append("\n").append("			<heading>-1.393494232815569</heading>");
		        placemark.append("\n").append("			<tilt>0</tilt>");
		        placemark.append("\n").append("			<range>298041.4619516017</range>");
		        placemark.append("\n").append("			<gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>");
		        placemark.append("\n").append("		</LookAt>");
		        placemark.append("\n").append("		<styleUrl>#msn_grn-blank</styleUrl>");
		        placemark.append("\n").append("		<Point>");
		        placemark.append("\n").append("			<coordinates>").append(EnderecosEncontrados.get(tam-2)).append(",").append(EnderecosEncontrados.get(tam-3)).append(",0</coordinates>");
		        placemark.append("\n").append("		</Point>");
		        placemark.append("\n").append("	</Placemark>");
		        placemark.append("\n");	
			} catch(ArrayIndexOutOfBoundsException e){
				System.out.print(e);
			}
		return placemark;
	}

//Plotar o cabeçalho do placemark
//Aqui podem ser aplicadas as personalizações do placemark e do kml
	public static StringBuffer plotarCabecalho(String nome){
		StringBuffer cabecalho = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		cabecalho.append("\n").append("<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\" xmlns:kml=\"http://www.opengis.net/kml/2.2\" xmlns:atom=\"http://www.w3.org/2005/Atom\">");
		cabecalho.append("\n").append("<Document>").append("\n");
		cabecalho.append("	<name>").append(nome).append(".kml</name>");
		cabecalho.append("\n").append("	<Style id=\"sn_grn-blank\">");
		cabecalho.append("\n").append("		<IconStyle>");
		cabecalho.append("\n").append("			<color>ff00ffff</color>");
		cabecalho.append("\n").append("			<Icon>");
		cabecalho.append("\n").append("				<href>http://maps.google.com/mapfiles/kml/paddle/grn-blank.png</href>");
		cabecalho.append("\n").append("			</Icon>");
		cabecalho.append("\n").append("			<hotSpot x=\"32\" y=\"1\" xunits=\"pixels\" yunits=\"pixels\"/>");
		cabecalho.append("\n").append("		</IconStyle>");
		cabecalho.append("\n").append("		<LabelStyle>");
		cabecalho.append("\n").append("			<scale>0.9</scale>");
		cabecalho.append("\n").append("		</LabelStyle>");
		cabecalho.append("\n").append("		<ListStyle>");
		cabecalho.append("\n").append("			<ItemIcon>");
		cabecalho.append("\n").append("				<href>http://maps.google.com/mapfiles/kml/paddle/grn-blank-lv.png</href>");
		cabecalho.append("\n").append("			</ItemIcon>");
		cabecalho.append("\n").append("		</ListStyle>");
		cabecalho.append("\n").append("	</Style>");
		cabecalho.append("\n").append("	<Style id=\"sh_grn-blank\">");
		cabecalho.append("\n").append("		<IconStyle>");
		cabecalho.append("\n").append("			<color>ff00ffff</color>");
		cabecalho.append("\n").append("			<scale>1.18182</scale>");
		cabecalho.append("\n").append("			<Icon>");
		cabecalho.append("\n").append("				<href>http://maps.google.com/mapfiles/kml/paddle/grn-blank.png</href>");
		cabecalho.append("\n").append("			</Icon>");
		cabecalho.append("\n").append("			<hotSpot x=\"32\" y=\"1\" xunits=\"pixels\" yunits=\"pixels\"/>");
		cabecalho.append("\n").append("		</IconStyle>");
		cabecalho.append("\n").append("		<LabelStyle>");
		cabecalho.append("\n").append("			<scale>0.9</scale>");
		cabecalho.append("\n").append("		</LabelStyle>");
		cabecalho.append("\n").append("		<ListStyle>");
		cabecalho.append("\n").append("			<ItemIcon>");
		cabecalho.append("\n").append("				<href>http://maps.google.com/mapfiles/kml/paddle/grn-blank-lv.png</href>");
		cabecalho.append("\n").append("			</ItemIcon>");
		cabecalho.append("\n").append("		</ListStyle>");
		cabecalho.append("\n").append("	</Style>");
		cabecalho.append("\n").append("	<StyleMap id=\"msn_grn-blank\">");
		cabecalho.append("\n").append("		<Pair>");
		cabecalho.append("\n").append("			<key>normal</key>");
		cabecalho.append("\n").append("			<styleUrl>#sn_grn-blank</styleUrl>");
		cabecalho.append("\n").append("		</Pair>");
		cabecalho.append("\n").append("		<Pair>");
		cabecalho.append("\n").append("			<key>highlight</key>");
		cabecalho.append("\n").append("			<styleUrl>#sh_grn-blank</styleUrl>");
		cabecalho.append("\n").append("		</Pair>");
		cabecalho.append("\n").append("	</StyleMap>").append("\n");
		return cabecalho;
	}
	
}
